package com.funcablaze.tpxterm;

import com.funcablaze.tpxterm.window.WindowController;
import com.google.gson.Gson;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.*;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

public class Application extends javafx.application.Application {
	private static AppConfig appConfig;
	public static final String
			QQ_Group = "https://qm.qq.com/q/vctpD8I9l6",
			GitHub = "https://qm.qq.com/q/vctpD8I9l6",
			Doc = "https://qm.qq.com/q/vctpD8I9l6",
			APP_NAME = "tpXterm - Transparent Xterm";
	
	@Override
	public void start(Stage stage) throws IOException {
		appConfig = AppConfig.load();
		loadThemeSafely(null);
		Locale defaultLocale = new Locale(appConfig.language);
		ResourceBundle bundle = ResourceBundle.getBundle("value/languages/messages", defaultLocale);
		Scene scene = new Scene(buildFXML("main", bundle, null), 1000, 600);
		stage.setTitle(APP_NAME);
		stage.setScene(scene);
		stage.show();
	}
	
	/**
	 * 加载主题
	 *
	 * @param theme 主题名称
	 */
	public static void loadThemeSafely(String theme) {
		boolean themeIsNull = theme == null;
		if (themeIsNull)
			theme = appConfig.theme;
		try {
			// 尝试直接加载CSS文件
			String cssPath = "/value/theme-atlantafx/" + theme + ".css";
			URL cssUrl = Application.class.getResource(cssPath);
			if (cssUrl != null) {
				Application.setUserAgentStylesheet(cssUrl.toExternalForm());
				if (!themeIsNull) {
					appConfig.theme = theme;
					appConfig.save();
				}
			}
		} catch (Exception e) {
			System.err.println("主题加载失败: " + e.getMessage());
		}
	}
	
	/**
	 * 切换语言
	 *
	 * @param language 语言名称
	 */
	public static void changeLanguage(@NotNull String language) {
		try {
			appConfig.language = language;
			appConfig.save();
		} catch (Exception e) {
			System.err.println("语言切换失败: " + e.getMessage());
		}
	}
	
	public static AppConfig getAppConfig() {
		return appConfig;
	}
	
	/**
	 * 加载FXML文件
	 *
	 * @param fxml 文件名
	 * @return 根节点
	 * @throws IOException 找不到文件
	 */
	public static Parent buildFXML(@NotNull String fxml, @NotNull ResourceBundle bundle, @Nullable WindowController.Callback callback) throws IOException {
		FXMLLoader fxmlLoader = new FXMLLoader(Application.class.getResource(String.format("/layout/%s.fxml", fxml)));
		fxmlLoader.setResources(bundle);
		Parent res = fxmlLoader.load();
		WindowController controller = fxmlLoader.getController();
		if (callback != null)
			controller.setInfo(callback);
		return res;
	}
	
	public static void openBrowser(@NotNull String url) throws IOException {
		Runtime.getRuntime().exec(String.format("cmd /c start %s", url));
	}
	
	public static void main(String[] args) {
		launch();
	}
	
	/**
	 * 获取JAR文件所在的目录路径
	 *
	 * @return 目录路径?Null
	 */
	@NotNull
	public static Path getJarDirectory() {
		String jarPath = Application.class
				.getProtectionDomain()
				.getCodeSource()
				.getLocation()
				.getPath();
		jarPath = new File(jarPath).getAbsolutePath();
		Path fullPath = Paths.get(jarPath);
		return fullPath.getParent();
	}
	
	public static class AppConfig {
		private static final File configFile = new File(getJarDirectory().toFile(), "conf/config.json");
		public String language;
		public String theme;
		public List<Host> recentFiles;
		
		public static AppConfig load() throws IOException {
			if (!configFile.exists()) {
				AppConfig appConfig = new AppConfig();
				appConfig.language = "zh-CN";
				appConfig.theme = "cupertino-dark";
				appConfig.recentFiles = new ArrayList<>();
				appConfig.save();
				return appConfig;
			} else {
				FileReader reader = new FileReader(configFile);
				AppConfig appConfig = new Gson().fromJson(reader, AppConfig.class);
				appConfig.save();
				return appConfig;
			}
		}
		
		public void save() throws IOException {
			if (!configFile.exists()) {
				if (!configFile.getParentFile().mkdirs())
					throw new IOException("Cannot create dirs.");
				if (!configFile.createNewFile())
					throw new IOException("Cannot create config file.");
			}
			FileWriter writer = new FileWriter(configFile);
			writer.write(new Gson().toJson(this));
			writer.close();
		}
		
		public AppConfig append(Host host) {
			if (recentFiles == null)
				recentFiles = new ArrayList<>();
			boolean isExist = false;
			for (Host h : recentFiles) {
				if (h.equals(host)) {
					isExist = true;
					break;
				}
			}
			if (!isExist)
				recentFiles.add(host);
			return this;
		}
		
		public String getLanguage() {
			return language;
		}
		
		public String getTheme() {
			return theme;
		}
		
		public static class Host implements Comparable<Host> {
			public String host;
			public int port;
			public String username;
			public String SftpPath = "/";
			
			public Host(String host, int port, String username) {
				this.host = host;
				this.port = port;
				this.username = username;
			}
			
			@Override
			public boolean equals(Object obj) {
				if (obj instanceof Host h) {
					return this.host.equals(h.host)
							& this.port == h.port
							& this.username.equals(h.username)
							& this.SftpPath.equals(h.SftpPath);
				}
				return false;
			}
			
			@Override
			public int compareTo(@NotNull Application.AppConfig.Host o) {
				if (this.host.equals(o.host)) {
					if (this.port == o.port)
						return this.username.compareTo(o.username);
					return this.port - o.port;
				} else {
					return this.host.compareTo(o.host);
				}
			}
		}
	}
}